#include "Server.h"

/*初始化服务器流程：
1. 创建套接字
2. 设置套接字端口可复用性
3. 配置服务器的网络地址的属性（一个结构体变量保存服务器的网络状态，即服务器套接字的相关属性）
4. 绑定套接字和网络地址属性（绑定成功后，使用该套接字收发数据）
5. 如果传入的端口为0，随机分配一个可用端口
*/
bool Server::_initServer(uint16_t * port) {
    this->_serverPort = *port;

    // 创建套接字
    this->_sererSocket = socket(PF_INET, SOCK_STREAM, 0);
    if(-1 == this->_sererSocket) {
        PrintLine("【服务器】创建套接字失败！");
        return false;
    }

    // 设置套接字端口可复用性（可以有效避免重启服务器后服务器的端口被占用的问题）
    int opt = 1;
    int ret = setsockopt(this->_sererSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if(-1 == ret) {
        PrintLine("【服务器】设置端口可复用性失败！");
        return false;
    }

    // 配置服务器的网络地址的属性
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;                // #define AF_INET PF_INET
    serverAddr.sin_port = htons(this->_serverPort); // 主机字节序转为网络字节序：host to network short
    serverAddr.sin_addr.s_addr = INADDR_ANY;        // ip地址

    // 绑定套接字和网络地址属性
    ret = bind(this->_sererSocket, (sockaddr *)&serverAddr, sizeof(serverAddr));
    if(0 > ret) {
        PrintLine("【服务器】绑定套接字失败！尝试更换服务器端口");  // 有时会出现端口冲突，导致bind失败
        return false;
    }

    // 如果传入的端口为0，随机分配一个可用端口
    if(0 == *port) {
        int sockLen = sizeof(serverAddr);
        ret = getsockname(this->_sererSocket, (sockaddr *)&serverAddr, (socklen_t *)&sockLen);
        if(-1 == ret) {
            PrintLine("【服务器】随机分配端口失败！");
            return false;
        }
        this->_serverPort = ntohs(serverAddr.sin_port); // 网络字节序转为主机字节序：network to host short
        *port = this->_serverPort;
    }

    PrintLine("【服务器】初始化服务器成功！");
    return true;
}

bool Server::_listen(int queueLength) {
    return listen(this->_sererSocket, queueLength) == 0;
}

bool Server::_accept(ClientData * clientData) {
    int addrLen = sizeof(clientData->clientAddr);
    // 成功，返回客户端套接字；否则，返回-1
    clientData->clientSocket = accept(this->_sererSocket, (sockaddr *)&clientData->clientAddr, (socklen_t *)&addrLen);
    return clientData->clientSocket != -1;
}

uint16_t Server::_getServerPort() {
    return this->_serverPort;
}

int Server::_getSererSocket() {
    return this->_sererSocket;
}